﻿using SuperX.Common.Abstract;
using SuperX.Common.Helper;
using SuperX.Common.Log;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace SuperX.Helper.OS
{
    public abstract class OSCommand : IHardwareInfo
    {
        public static OSCommand GetNewOSCommand()
        {
            OSCommand instance = null;
#if NETSTANDARD2_0
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                instance = WindowsCommand.GetNewWindowsCommand();
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                instance = LinuxCommand.GetNewLinuxCommand();
            }
#elif NET40 || NET45 || NET461
            instance = WindowsCommand.GetNewWindowsCommand();
#endif
            if (instance == null)
            {
                throw new NotImplementedException("有新的未兼容的操作系统");
            }
            instance.Register();
            return instance;
        }

        public static Type LoadType(string field, Type baseType)
        {
            try
            {
                CheckUtil.NotNullOrWhiteSpace(field, nameof(field));

                if (baseType == null)
                {
                    baseType = typeof(OSCommand);
                }

                var types = AppDomain.CurrentDomain.GetAssemblies()
                           .SelectMany(t => t.GetTypes())
                           .Where(t => t.IsClass && t.IsSubclassOf(baseType));
                foreach (var type in types)
                {
                    if (type.GetCustomAttributes(typeof(CommandAttribute), true).FirstOrDefault() is CommandAttribute cmdAttr)
                    {
                        if (cmdAttr.MatchFields.Any(f => Regex.IsMatch(field, f)))
                        {
                            return type;
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException ex)
            {
                StringBuilder sb = new StringBuilder();
                foreach (Exception exSub in ex.LoaderExceptions)
                {
                    sb.AppendLine(exSub.Message);
                    FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
                    if (exFileNotFound != null)
                    {
                        if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
                        {
                            sb.AppendLine("Fusion Log:");
                            sb.AppendLine(exFileNotFound.FusionLog);
                        }
                    }
                    sb.AppendLine();
                }
                string errorMessage = sb.ToString();
                Logger.Error(errorMessage);
            }
            return null;
        }

        public void Register()
        {
            MachineHardwareInfoUtil.RegisterHardwareInfoInstance(this);
        }

        #region 路径

        public abstract string GetIoTDataDir();

        public abstract string GetGatewayBaseDir();

        public abstract string GetGatewayCurrentDir();

        public abstract string GetLogDir();

        public abstract string GetSystemTmpDir();

        public abstract string GetProjectDownLoadDir();

        public abstract string GetGatewayOutputBaseDir();

        #endregion 路径

        #region 信息统计

        /// <summary>
        /// 内存大小
        /// </summary>
        /// <param name="processName"></param>
        /// <returns></returns>
        public abstract double GetMemory(string processName);

        /// <summary>
        /// 操作系统的简短描述
        /// </summary>
        /// <returns></returns>
        public abstract string GetOSDescription();

        /// <summary>
        /// 操作系统的启动时间
        /// </summary>
        /// <returns></returns>
        public abstract DateTime GetGatewayStartTime();

        public abstract List<string> GetNetAdapterMacAddress();

        public abstract string GetMotherBoardID();

        public abstract string GetCpuID();

        /// <summary>
        /// 获取网关唯一机器码
        /// </summary>
        public string GetUniqueMachineCode()
        {
            string str = string.Empty;
            try
            {
                //获取网络适配器网卡地址
                List<string> netAdapterMacAddrs = GetNetAdapterMacAddress();
                if (netAdapterMacAddrs?.Count > 0)
                {
                    return str = "IoT" + netAdapterMacAddrs[0];//返回第一个网卡，一般第一个网卡就是本地连接的那个
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
            }
            return str;
        }

        public abstract List<string> GetHardwareInfo();

        #endregion 信息统计

        #region 进程管理

        public abstract void StartBrowser(string uri);

        public abstract List<Process> GetProcesses(string processName);

        public abstract void StartProcess(string fileFullPathName);

        public void StopProcess(string processName, string reason)
        {
            try
            {
                var processes = GetProcesses(processName);
                //判断是否有相应的进程在运行
                if (processes?.Count > 0)
                {
                    Logger.Info($"（{reason}）停止进程:{processName}");
                    foreach (var item in processes)
                    {
                        item.Kill();
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Info($"（{reason}）停止进程:{processName}，出现异常");
                Logger.Exception(ex);
            }
        }

        /// <summary>
        /// 立即或尽快结束当前进程
        /// </summary>
        /// <param name="processName"></param>
        public abstract void ExitSelfProcess(string processName = null);

        public abstract void GatewayRestart(string fileFullPathName, string reason, string processName);

        public abstract void MonitorHelperStopProcess(string processName, string reason, string serviceName);

        public abstract void MonitorHelperStartProcess(string processName, string reason, string serviceName);

        public virtual void ProcessManagerReStartProcess(string fileFullPathName)
        {
            //Logger.Trace("路径为："+ fileFullPathName);
            if (string.IsNullOrEmpty(fileFullPathName)) return;
            string processName = Path.GetFileNameWithoutExtension(fileFullPathName);//获取进程名
            StopProcess(processName, string.Empty);
            StartProcess(fileFullPathName);
        }

        public virtual void ProcessManagerStartProcess(string fileFullPathName)
        {
            Logger.Info(string.Format("{0} 准备启动进程：{1}", DateTime.Now, fileFullPathName));
            //判断文件是否存在
            if (!CheckIfFileExisted(fileFullPathName))
            {
                Logger.Warn(string.Format("{0} {1}文件不存在", DateTime.Now, fileFullPathName));
                return;
            }

            StartProcess(fileFullPathName);
        }

        private bool CheckIfFileExisted(string fileFullPathName)
        {
            try
            {
                // Logger.Trace("判断文件时路径为：" + fileFullPathName);
                fileFullPathName = fileFullPathName.Replace(@"\", "/");
                return File.Exists(fileFullPathName);
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                return false;
            }
        }

        #endregion 进程管理

        /// <summary>
        /// 检查更新程序锁是否被占用
        /// </summary>
        /// <param name="invokeMessage"></param>
        public abstract void CheckOtherUpdate(InvokeMsg invokeMessage);

        public virtual int GetThreadId()
        {
            return System.Threading.Thread.CurrentThread.ManagedThreadId;
        }

        public virtual string GetSourceName()
        {
            return Environment.MachineName;
        }

        public virtual string GetAppName()
        {
            return Process.GetCurrentProcess().MainModule.ModuleName;
        }

        #region IP管理

        public abstract bool IsSupportIPManager();

        public abstract Tuple<bool, bool, List<string>> GetAutoAndDns(string adapterName, IPInterfaceProperties property, string ipv4);

        public abstract bool SetIPAddress(string ip, string editIp, string submask, string gateway, string[] dns, bool dnsAuto, bool dchpAuto, string mac);

        public abstract bool EnableDHCP(string name, string identifyIp, bool dnsAuto, string[] dnsArray);

        #endregion IP管理

        #region NTP(时间同步)

        public class NTPContext
        {
            public bool EnableNTPServer { get; set; }

            public bool EnableNTPClient { get; set; }

            public string NTPServerIP { get; set; }
        }

        public abstract void GetNTP(NTPContext ntpContext);

        public abstract void SetNTP(NTPContext ntpContext);

        #endregion NTP(时间同步)

        #region 更新软件

        public abstract bool UpdateFileExists();

        /// <summary>
        /// 更新软件信息
        /// </summary>
        protected class UpdateSoftwareInfo
        {
            /// <summary>
            /// 文件名和放置的相对路径
            /// key：Name，value：RelativePath
            /// </summary>
            public Dictionary<string, string> FileNameAndRelativePaths = new Dictionary<string, string>();

            /// <summary>
            /// 更新软件的最外层临时文件夹
            /// </summary>
            [JsonIgnore]
            public string UpdateSoftwareTmpDir { get; set; }

            /// <summary>
            /// 放置有更新文件的文件夹路径
            /// </summary>
            [JsonIgnore]
            public string SubDir { get; set; }
        }

        public abstract void StartUpdate(string updateSoftwareTmpDir, string subDir);

        public abstract void StartUpdate(string updateSoftwareTmpDir);

        #endregion 更新软件

        #region openssh-server

        /// <summary>
        /// 检测ssh-server是否运行
        /// </summary>
        /// <returns></returns>
        public abstract FunctionState GetSSHServerState();

        /// <summary>
        /// 重启ssh-server
        /// </summary>
        public abstract void RestartSSHServer();

        #endregion openssh-server

        public abstract string ScriptExecute(string content);

        public abstract string FormatDirectorySeparatorChar(string content);

        #region 共享文件夹

        /// <summary>
        /// 创建挂载路径
        /// </summary>
        /// <param name="dirPath">要挂载的路径</param>
        public abstract void CreateMountDir(string dirPath);

        /// <summary>
        /// 移除挂载路径
        /// </summary>
        /// <param name="dirPath">挂载的路径</param>
        public abstract void RemoveMountDir(string dirPath);

        /// <summary>
        /// 删除文件夹
        /// </summary>
        /// <param name="dirPath">路径</param>
        public abstract void DeleteDir(string dirPath);

        #endregion 共享文件夹

        #region OPCUAServer进程管理

        public abstract void StartOPCUAServer();

        public abstract void StopOPCUAServer();

        public abstract bool CheckIfOPCUAServerIsRunning();

        #endregion OPCUAServer进程管理

        /// <summary>
        /// 获取网卡的所有IP
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetCurrentHostIpList()
        {
            return System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
                .Select(p => p.GetIPProperties())
                .SelectMany(p => p.UnicastAddresses)
                .Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPAddress.IsLoopback(p.Address))
                .Select(ip => ip.Address.ToString());
        }
    }
}